/*
 * TowerRedOne.cs
 *
 * Created on December 9, 2007, 2:13 PM
 *
 * Copyright (C) 2007-2008  Hylke van der Schaaf
 * Copyright (C) 2010       Mathijs Miermans
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, in version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;


namespace HexTD
{
	public class TowerRedThree : TowerBase
	{

		public static int price = 2500000;
		public static int damage = 15000000;
		public static float range = 15f;
		public static float spreadRadiusBase = 6f;
		public static float projectileSpeedBase = 0.1f;
		//
		private int fireAt = -1;
		private COLOR damageColor = COLOR.RED;
		private int coolDown = 0;
		private int coolDownTime = 59;
		//
		private Color transColor;
		private float spreadRadius;
		private float spreadRadius2;
		private float projectileSpeed;
		//
		private List<Projectile> projectiles = new List<Projectile>();
#if PORT
		private Image[] projectileImg;
#endif

		/**
		 * Creates a new instance of TowerRedThree
		 */
		public TowerRedThree(Game game, Context context, Hex hex)
			: base(game, TowerFactory.type.redThree, price, damage, range)
		{
			this.lineColor = Color.Red;
			this.transColor = new Color(50, this.lineColor.R, this.lineColor.G, this.lineColor.B);
			this.doInit(context, hex);
		}

		public override void doTick(int gameTime)
		{
#if PORT
			if (this.coolDown > 0) {
				this.coolDown--;
			} else {
				int enemyNr = this.findEnemy(this.fireAt, false);
				this.fireAt = enemyNr;

				if (enemyNr >= 0) {
					Projectile p = new Projectile();
					p.target = this.context.enemies[enemyNr];
					p.x = this.xFloat;
					p.y = this.yFloat;
					this.projectiles.Add(p);
					this.coolDown = this.coolDownTime;
				}
			}

			for (int ip = this.projectiles.Count - 1; ip >= 0; ip--) {
				Projectile p = this.projectiles.get(ip);

				if (!p.target.validTarget()) {
					int enemyNr = this.findEnemyClosest(p.x, p.y, 100, new int[0]);
					if (enemyNr >= 0) {
						p.target = this.context.enemies[enemyNr];
					} else {
						p.target = null;
						this.projectiles.Remove(ip);
						p.status = 2;
					}
				} else {
					float dx, dy, r, factor;
					if (p.status == 0) {
						dx = p.target.getX() - p.x;
						dy = p.target.getY() - p.y;
						r = (float) Math.Sqrt(dx * dx + dy * dy);
						factor = this.projectileSpeed / r;
						if (factor < 1) {
							dx *= factor;
							dy *= factor;
							p.x += dx;
							p.y += dy;
						} else {
							// HIT!
							p.x = p.target.getX();
							p.y = p.target.getY();
							p.status = 1;
						}
					}
					if (p.status == 1) {
						p.targetsHit = this.findEnemiesInRange(p.x, p.y, this.spreadRadius);
						int damage;
						float rs;
						EnemySprite enemy;
						for (int i = 0; i < p.targetsHit.length; i++) {
							enemy = p.targetsHit[i];
							dx = p.x - enemy.getX();
							dy = p.y - enemy.getY();
							rs = (float) Math.Sqrt(dx * dx + dy * dy);
							damage = Math.Round(this.damageCurrent * (1 - rs / this.spreadRadius));
							enemy.doDamage(damage, this.damageColor);
						}
						p.status++;
					} else if (p.status > 1) {
						p.target = null;
						this.projectiles.Remove(ip);
					}
				}
			}
#endif
		}

		public override string getStatusString()
		{
			string retString = "";
			retString += "<h1>Red Tower 3</h1>" +
					"<p>" +
					"<b>Level:</b> " + (1 + this.level) + "<br>\n" +
					"<b>Damage:</b> " + this.damageText + "<br>\n" +
					"<b>Range:</b> " + this.rangeText + "<br>" +
					"</p>\n";
			return retString;
		}

		public override string getInfoString()
		{
			string retString = "";
			retString += "<h1>Red Tower 3</h1>" +
					"<p>" +
					"Tower firing slow, heavy homing projectiles with a large splash radius. The projectiles might be to slow to catch some enemies!" +
					"<br>Strong against red enemies, very weak against green enemies." +
					"</p>" +
					"<p>" +
					"<b>Price:</b> " + price + "<br>" +
					"<b>Damage:</b> " + this.damageCurrent + " + splash<br>" +
					"<b>Range:</b> " + rangeCurrent + "<br>" +
					"<b>Refire rate:</b> 0.33/s" +
					"</p>";
			return retString;
		}

		protected override void generateShapes()
		{
#if PORT
			Cache cache = this.context.getCache();

			float width = this.context.hexPaintWidth;
			int shapeCount = 7;
			this.shapes = new Shape[shapeCount];
			this.shapes[0] = new Ellipse.Float(-0.5f * this.paintScale, -0.5f * this.paintScale, 1.0f * this.paintScale, 1.0f * this.paintScale);
			this.shapes[1] = new Ellipse.Float(-0.5f * this.paintScale, -0.5f * this.paintScale, 1.0f * this.paintScale, 1.0f * this.paintScale);
			this.shapes[2] = new Ellipse.Float(-1.0f * this.context.strokeScale, -1.0f * this.context.strokeScale, 2.0f * this.context.strokeScale, 2.0f * this.context.strokeScale);
			this.shapes[3] = new LineSegment.Float(width, 0.5f * this.paintScale, 0, 0);
			this.shapes[4] = new LineSegment.Float(-width, -0.5f * this.paintScale, 0, 0);
			this.shapes[5] = new LineSegment.Float(0.5f * width, -0.25f * this.paintScale, 0, 0);
			this.shapes[6] = new LineSegment.Float(-0.5f * width, 0.25f * this.paintScale, 0, 0);

			this.shapeAction = new int[shapeCount];
			this.shapeAction[0] = 2;
			this.shapeAction[1] = 1;
			this.shapeAction[2] = 1;
			this.shapeAction[3] = 1;
			this.shapeAction[4] = 1;
			this.shapeAction[5] = 1;
			this.shapeAction[6] = 1;

			this.shapeColor = new Color[shapeCount];
			this.shapeColor[0] = this.transColor;
			this.shapeColor[1] = this.lineColor;
			this.shapeColor[2] = this.lineColor;
			this.shapeColor[3] = this.lineColor;
			this.shapeColor[4] = this.lineColor;
			this.shapeColor[5] = this.lineColor;
			this.shapeColor[6] = this.lineColor;

			this.strokes = new Brush[shapeCount];
			this.strokes[0] = new Brush(2.0f * this.context.strokeScale, Brush.CAP_ROUND, Brush.JOIN_BEVEL);
			this.strokes[1] = this.strokes[0];
			this.strokes[2] = this.strokes[0];
			this.strokes[3] = this.strokes[0];
			this.strokes[4] = this.strokes[0];
			this.strokes[5] = this.strokes[0];
			this.strokes[6] = this.strokes[0];
			this.spreadRadius = this.spreadRadiusBase;
			this.spreadRadius2 = this.spreadRadius * this.spreadRadius;
			this.projectileSpeed = projectileSpeedBase;

			if (cache.hasBufImgArr("Red3ProjImagArr")) {
				this.projectileImg = cache.getBufImgArr("Red3ProjImagArr");
			} else {
				float pWidth = width / 7f;
				float pScale = this.paintScale / 7f;
				int imgW = (int) (pScale * 2) + 2;
				int imgH = (int) (pScale * 2) + 2;
				this.projectileImg = new Image[3];
				float[,] pPoints = Geometry.createPolyCoords(pScale, (float) imgW / 2, (float) imgH / 2);
				RotateTransform atr = new RotateTransform();
				for (int i = 0; i < this.projectileImg.length; i++) {
					atr.setToIdentity();
					atr.rotate(Math.PI * i * 2 / 6 / 3, (float) imgW / 2, (float) imgH / 2);

					this.projectileImg[i] = new Image(imgW, imgH, Image.TYPE_INT_ARGB_PRE);
					//GeneralPath polyHex = Geometry.coordsToGeneralPath(pPoints, true);
					Canvas g2 = this.projectileImg[i].createGraphics();
					g2.transform(atr);
					g2.setColor(this.lineColor);
					//g2.draw(polyHex);
					g2.draw(new LineSegment.Float(pPoints[0, 0], pPoints[0, 1], pPoints[3, 0], pPoints[3, 1]));
					g2.draw(new LineSegment.Float(pPoints[1, 0], pPoints[1, 1], pPoints[4, 0], pPoints[4, 1]));
					g2.draw(new LineSegment.Float(pPoints[2, 0], pPoints[2, 1], pPoints[5, 0], pPoints[5, 1]));
					g2.dispose();
				}
				cache.putBufImgArr("Red3ProjImagArr", this.projectileImg);
			}
#endif
		}

		public override void DrawEffects(GameTime gameTime)
		{
#if PORT
			Brush defaultStroke = g2.getStroke();

			g2.setColor(this.lineColor);

			float pw = (float) this.projectileImg[0].getWidth() / 2f;
			float ph = (float) this.projectileImg[0].getHeight() / 2f;
			Projectile[] paintProjectiles = new Projectile[0];
			paintProjectiles = this.projectiles.toArray(paintProjectiles);
			for (int ip = 0; ip < paintProjectiles.Length; ip++) {
				Projectile p = paintProjectiles[ip];
				if (p.status == 0) {
					g2.drawImage(this.projectileImg[p.anim], Math.Round(p.x * paintScale + this.context.offsetX - pw), Math.Round(p.y * paintScale + this.context.offsetY - ph), null);
					p.anim++;
					if (p.anim >= this.projectileImg.length) {
						p.anim = 0;
					}
				} else {
					EnemySprite[] targets = p.targetsHit;
					if (targets != null) {
						for (int i = 0; i < targets.Length; i++) {
							g2.draw(new LineSegment.Float(p.x * paintScale + this.context.offsetX, p.y * paintScale + this.context.offsetY, p.targetsHit[i].getPaintX(), p.targetsHit[i].getPaintY()));
						}
					}
				}

			}

			g2.setStroke(defaultStroke);
#endif
		}
	}
}